home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource4
/
233_01
/
make.c
< prev
next >
Wrap
Text File
|
1987-07-01
|
13KB
|
527 lines
/*
* Program Name : MAKE.C
* Author : Allen Holub
* Implementor : Kenji Hino
* Compiler : Microsoft ver. 4.0, Lattice C ver. 3
* Description : MAKE is the program that maintains programs.
* MAKE takes resposibility for recompiling or linking
* any source or object codes if any of them has
* updated.
*/
#include "make.h"
void main(argc, argv)
char **argv;
int argc;
{
int dependancies(), make(), err();
if( !(Makefile = fopen(MAKEFILE, "r")) )
err("can't open %s\n", MAKEFILE);
if( !dependancies() )
err("Nothing to make");
else
make( argc > 1 ? argv[1] : First);
} /* main end */
char *gmem( numbytes )
int numbytes;
{
/* Get numbytes from malloc. Print an error messages and
abort if malloc fails, otherwise return a pointer to
the memory.
*/
char *calloc();
char *p;
int err();
if( !( p = calloc(1, numbytes) ))
err("Out of memory");
return p;
} /* gmem end */
char **stov(str, maxvect)
char *str;
int maxvect;
{
/* "Str" is a string of words seperated from each other by
white space. Stov returns an argv-like array of pointers
to chracter pointers, one to each word in the original
string. The white-space in the original string is replaced
with nulls. The array of pointers is null-terminated
array. The program is aborted of it can't get memory.
*/
char **vect, **vp;
char *gmem();
vp = vect = (char **) gmem( (maxvect + 1) * sizeof(str) );
while( *str && --maxvect >= 0 )
{
skipwhite(str);
*vp++ = str;
skipnonwhite(str);
if(*str)
*str++ = 0;
}
*vp = 0;
return(vect);
} /* stov end */
long gtime( file )
char *file;
{
/* Return the time and date for file.
The DOS time and date are concatenated to form one
large number. Note that the high bit of this number
will be set to 1 for all dates after 2043, which will
cause the date comparisons done in make() to not work.
THIS ROUTINE IS NOT PORTABLE (because it assumes a 32 bit
long).
*/
long time;
int fd;
int open(), err(), close();
#ifdef MICRO_C
struct stat buf;
int fstat();
int result;
#endif
#ifdef LATTICE_C
long getft();
#endif
if ( (fd = open (file, O_RDONLY)) == -1 )
return DEFTIME;
#ifdef MICRO_C
if ( (result = fstat (fd, &buf)) == -1 )
err("DOS returned error from date/time request");
time = buf.st_atime;
#endif
#ifdef LATTICE_C
/* LATTICE uses a different time structure from one returned by */
/* gmtime() so that it doesn't show the same file time as one you get */
/* by "dir" command. However, it still can tell the difference */
/* between new and old files. */
if ( (time = getft (fd)) == -1 )
err("DOS returned error from date/time request");
#endif
if ( close (fd) )
err("DOS returned error from file close request");
return time;
} /* gtime end */
TNODE *makenode()
{
/* Create a TNODE, filling it from the makefile
and return a pointer to it. Return NULL if there are no more
objects in the makefile.
*/
char *line, *lp;
TNODE *nodep;
char *getline(), **stov(), **getblock(), *gmem();
int err();
long gtime();
/* First, skip past any blank lines or comment lines.
Return NULL if we reach the end of file
*/
do{
if( (line = getline(MAXLINE, Makefile)) == NULL )
return( NULL );
} while ( *line == 0 || *line == COMMENT );
/* At this point we've gotten what should be the dependancy
line. Position lp to point at the colon.
*/
for( lp = line; *lp && *lp != ':'; lp++)
;
/* If we find the colon position, lp to point at the first
non-white character following the colon.
*/
if( *lp != ':' )
err("missing ':'"); /* This will abort the program */
else
for( *lp++ = 0; iswhite(*lp) ; lp++)
;
/* Allocate and initialize the TNODE */
nodep = (TNODE *) gmem( sizeof(TNODE) );
nodep->being_made = line;
nodep->time = gtime( line );
nodep->depends_on = stov( lp, MAXDEP );
nodep->do_this = getblock( Makefile );
return( nodep );
} /* makenode end */
int dependancies()
{
/* Manufacture the binary tree of objects to make. First
is a pointer to the first target file listed in the
makefile (i.e. the one to make if one isn't explicitly
given on the command line). Root is the tree's root pointer.
*/
TNODE *node, *makenode();
int err(), tree();
if( node = makenode() )
{
First = node->being_made;
if( !tree(node, &Root) )
err("Can't insert first node into tree !!!\n");
while( node = makenode() )
if( !tree(node, &Root) )
free(node);
return 1;
}
return 0;
} /* dependancies end */
char *getline( maxline, fp)
int maxline;
FILE *fp;
{
/* Get a line from the stream pointed to by fp.
"Maxline" is the maximum input line size ( including the
terminating null. A \ at the end of line is
recognized as a line continuation, ( the lines
are concatenated). Buffer space is gotten from malloc.
If a line is longer than maxline it is truncated (i.e.
all characters from the maxlineth until a \n or EOF is
encountered are discarded.
Return: NULL on a malloc failure or the end of file.
A pointer to the malloced buffer on success.
*/
static char *buf;
register char *bp;
register int c, lastc;
char *malloc(), *strcpy();
/* Two buffers are used, Here, we are getting a worst-case buffer
that will hold the longest possible line. Later on we'll copy
the string into a buffer that's the correct size.
*/
if( !(bp = buf = malloc(maxline)) )
return NULL;
while(1)
{
/* Get the line from fp. Terminate after maxline
characters and ignore \n following a \.
*/
Inputline++; /* Update input line number */
for( lastc=0; (c = fgetc(fp)) != EOF && c!='\n'; lastc = c)
if( --maxline > 0 )
*bp++ = c;
if( !(c == '\n' && lastc == '\\') )
break;
else if(maxline > 0) /* erase the \ */
--bp;
}
*bp = 0;
if( (c == EOF && bp == buf) || !(bp = malloc((bp-buf) + 1)) )
{
/* If EOF was the first character on the line or
malloc fails when we try to get a buffer, quit.
*/
free(buf);
return( NULL );
}
strcpy (bp, buf); /* Copy the worst-case buffer to the one */
/* that is the correct size and ... */
free ( buf ); /* free the original, worst-case buffer, */
return ( bp ); /* returning a pointer to the copy */
} /* getline end */
char **getblock( fp )
FILE *fp;
{
/* Get a block from standard input. A block is a sequences of
lines terminates by a blank line. The block is returned as
an array of pointers to strings. At most MAXBLOCK lines can
be in a block. Leading white space is stripped.
*/
char *p, *lines[MAXBLOCK], **blockv = lines, *gmem();
int blockc = 0;
char *memcpy(), *getline(), *gmem();
int err();
do {
if( !( p = getline(MAXLINE, Makefile) ))
break;
skipwhite(p);
if( ++blockc <= MAXBLOCK )
*blockv++ = p;
else
err("action too long (max = %d lines)", MAXBLOCK);
} while(*p);
/* Copy the blockv array into a safe place. Since the array
returned by getblock is NULL terminated, we need to
increment block first.
*/
blockv = (char **) gmem( (blockc + 1) * sizeof(blockv[0]) );
memcpy( blockv,lines, blockc * sizeof(blockv[0]) );
blockv[blockc] = NULL;
return blockv;
} /* getblock end */
int err( msg, param)
char *msg;
int param;
{
/* Print the error message and exit the program. */
fprintf(stderr, "Mk (%s line %d): ", MAKEFILE, Inputline);
fprintf(stderr, msg, param);
exit(1);
} /* err end */
int serr( msg, param )
char *msg, *param;
{
/* same as err() except the parameter is a string pointer
instead pf an int.
*/
fprintf(stderr, "Mk (%s line %d): ", MAKEFILE, Inputline);
fprintf(stderr, msg, param);
exit(1);
} /* serr end */
int make(what)
char *what;
{
/* Actually do the make. the dependancy tree is descended
recursively and of required, the dependancies are
adjusted. Return 1 if anything was done, 0 otherwise.
*/
TNODE *snode; /* Source file node pointer */
TNODE *dnode; /* Dependant file node pointer */
int doaction = 0; /* If true do the action */
static char *zero = (char *)0;
char **linev = &zero;
TNODE *find();
int make(), serr(), system();
#ifdef DEBUG
static int recurlev = 0; /* Recursion level */
printf("make (lev %d): making <%s> \n", recurlev, what );
#endif
if( !(snode = find(what, Root)) )
serr("Don't know how to make <%s>\n", what);
if( !*(linev = snode->depends_on) ) /* If no dependancies */
doaction++; /* always do the action. */
for( ; *linev; linev++) /* Process each dependancy */
{
#ifdef DEBUG
recurlev++;
#endif
make( *linev );
#ifdef DEBUG
recurlev--;
#endif
if( !(dnode = find(*linev, Root)) )
serr("Don't know how to make <%s>\n", *linev);
#ifdef DEBUG
printf("make (lev %d):source file ", recurlev);
ptime( what, snode->time );
printf("make (lev %d):depenadant file ", recurlev);
ptime( *linev, dnode->time);
#endif
if( snode->time <= dnode->time )
{
/* If source node is older than (time is less than)
dependant node, do something. If the times are
equal, assume that neither file exists but that
the action will create them, and do the action.
*/
#ifdef DEBUG
printf("make (lev %d): %s older than %s\n",
recurlev, what, *linev);
#endif
doaction++;
}
#ifdef DEBUG
else
printf("make (lev %d): %s younger than %s\n", recurlev,
what, *linev );
#endif
}
if( doaction )
{
#ifdef DEBUG
printf("make (lex, %d): doing action:\n",
recurlev, *linev, what);
#endif
for( linev = snode->do_this; *linev; linev++)
{
printf("%s\n", *linev); /* Echo action to screen */
#ifndef DEBUG
if( system(*linev) )
serr("Can't process <%s>\n", *linev);
#endif
/* Change the source file's time to refelect
any modification.
*/
snode->time = gtime( snode->being_made );
}
}
#ifdef DEBUG
printf("make (lev %d): exiting\n", recurlev );
#endif
return doaction;
} /* make end */
TNODE *find( key, root )
char *key;
TNODE *root;
{
/* If key is in the tree pointed to by root, return a pointer
to it, else reutrn 0.
*/
register int notequal ;
TNODE *find();
int strcmp();
if( !root )
return 0;
if( !(notequal = strcmp(root->being_made, key)) )
return (root);
return( find(key, (notequal > 0) ? root->lnode : root->rnode) );
} /* find end */
int tree(node, rootp)
TNODE *node, **rootp;
{
/* If node's key is in the tree pointed to by rootp, return 0
else put it into the tree and return 1.
*/
register int notequal;
int tree(),strcmp();
if( *rootp == NULL )
{
*rootp = node;
return 1;
}
if ( !(notequal = strcmp( (*rootp)->being_made, node->being_made)) )
return 0;
return( tree( node, notequal > 0 ? &((*rootp)->lnode)
: &((*rootp)->rnode)) );
} /* tree end */
#ifdef DEBUG
/* Debugging Routine */
int ptime( file, time )
char *file;
long time;
{
/* Print out the time and date field of a TNODE
File is the file name.
*/
char *ctime();
printf("%s; ", file);
printf("%s", ctime(&time));
printf("\n");
} /* ptime end */
pnode( node )
TNODE *node;
{
/* Print out the tree node pointed to by "node". */
char **linev;
printf("+----------------------------------------\n");
printf("| node at 0x%x\n", node);
printf("+----------------------------------------\n");
printf("| lnode = 0x%x, rnode = 0x%x \n ", node->lnode, node->rnode);
printf("| time = 0x%lx, =", node->time);
printf("| target = <%s>\n", node->being_made);
printf("| dependancies:\n");
for( linev = node->depends_on; *linev; printf("|\t%s\n", *linev++));
printf("| actions:\n");
for( linev = node->do_this; *linev; printf("|\t%s\n", *linev++));
printf("+----------------------------------------\n");
} /* pnode end */
trav( root )
TNODE *root;
{
/* Do an in-order traversal of the tree, printing the
node's contents as you go.
*/
if( root == NULL )
return;
trav( root->lnode );
pnode( root );
trav( root->rnode );
} /* trav end */
#endif